﻿using System;
using System.Linq.Expressions;

namespace NameOfSpike
{
    // based on: http://joelabrahamsson.com/getting-property-and-method-names-using-static-reflection-in-c/
    public static class StaticReflection
    {
        /*public static string NameOf<T>(this T instance, Expression<Func<T, object>> expression)
        {
            return StaticReflection.NameOf(expression);
        }

        public static string NameOf<T>(Expression<Func<T, object>> expression)
        {
            if (expression == null) { throw new ArgumentNullException("expression"); }
            return StaticReflection.NameOf(expression.Body);
        }

        public static string NameOf<T>(this T instance, Expression<Action<T>> expression)
        {
            return StaticReflection.NameOf(expression);
        }

        public static string NameOf<T>(Expression<Action<T>> expression)
        {
            if (expression == null) { throw new ArgumentNullException("expression"); }
            return StaticReflection.NameOf(expression.Body);
        }*/

        public /*private */static string NameOf(Expression expression)
        {
            if (expression == null) { throw new ArgumentNullException("expression"); }
            
            var memberExpression = expression as MemberExpression;
            if (memberExpression != null)
            {
                // reference type property or field
                return memberExpression.Member.Name;
            }

            var callExpression = expression as MethodCallExpression;
            if (callExpression != null)
            {
                // reference type method
                return callExpression.Method.Name;
            }

            var unaryExpression = expression as UnaryExpression;
            if (unaryExpression != null)
            {
                // property, field of method returning value type
                return StaticReflection.NameOf(unaryExpression);
            }

            throw new ArgumentException("Invalid expression");
        }

        private static string NameOf(UnaryExpression unaryExpression)
        {
            if (unaryExpression.Operand is MethodCallExpression)
            {
                var methodExpression = (MethodCallExpression)unaryExpression.Operand;
                return methodExpression.Method.Name;
            }

            return ((MemberExpression)unaryExpression.Operand).Member.Name;
        }
    }
}
